package com.tonyodev.fetch2rx;

import ohos.utils.Pair;

import com.tonyodev.fetch2.CompletedDownload;
import com.tonyodev.fetch2.Download;
import com.tonyodev.fetch2.Error;
import com.tonyodev.fetch2.FetchConfiguration;
import com.tonyodev.fetch2.FetchGroup;
import com.tonyodev.fetch2.FetchListener;
import com.tonyodev.fetch2.NetworkType;
import com.tonyodev.fetch2.Request;
import com.tonyodev.fetch2.Status;
import com.tonyodev.fetch2.exception.FetchException;
import com.tonyodev.fetch2.fetch.FetchModulesBuilder;
import com.tonyodev.fetch2core.DownloadBlock;
import com.tonyodev.fetch2core.Downloader;
import com.tonyodev.fetch2core.Extras;
import com.tonyodev.fetch2core.FetchObserver;
import com.tonyodev.fetch2core.FileResource;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A light weight file download manager for Android with Rx features.
 * Features: Background downloading,
 * Queue based Priority downloading,
 * Pause & Resume downloads,
 * Network specific downloading and more...
 *
 * @since 2021-05-20
 */
public interface RxFetch {
    /**
     * Returns true if this instance of fetch is closed and cannot be reused.
     */
    boolean isClosed = false;
    /**
     * The namespace which this instance of fetch operates in. An app can
     * have several instances of Fetch with different namespaces.
     *
     * @see com.tonyodev.fetch2.FetchConfiguration
     */
    String namespace = null;
    /**
     * Get the FetchConfiguration object that created this instance of Fetch.
     * Note: If you have updated settings on this instance of Fetch, this object
     * will not have these updated settings.
     */
    FetchConfiguration fetchConfiguration = null;

    /**
     * 释放rxfetch
     *
     * @return 操作成功返回true，否则false
     */
    boolean isClosed();

    /**
     * Queues a request for downloading. If Fetch fails to enqueue the request,
     * func2 will be called with the error.
     * Errors that may cause Fetch to fail the enqueue are :
     * 1. No storage space on the device.
     * 2. Fetch is already managing the same request. This means that a request with the same url
     * and file name is already managed.
     *
     * @param request Download Request
     * @return Convertible with request result.
     * Fetch may update a request depending on the initial request's Enqueue Action.
     * Update old request references with this request.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Request> enqueue(Request request);

    /**
     * Queues a list of requests for downloading. If Fetch fails to enqueue a
     * download request because an error occurred, all other request in the list will
     * fail. Func2 will be called with the error message.
     * Errors that may cause Fetch to fail the enqueue are :
     * 1. No storage space on the device.
     * 2. Fetch is already managing the same request. This means that a request with the same url
     * and file name is already managed.
     *
     * @param requests Request List
     * @return Convertible with requests list. Returns a list with a pair<Request,Error> for each enqueued request.
     * If the pair's second parameter is Error.NONE. this indicates that the request
     * was enqueued successfully. If the Error is not ERROR.NONE. This indicates
     * that the request was not enqueued for the specified reason.
     * Fetch may update a request depending on the initial request's Enqueue Action.
     * Update old request references with this request.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Pair<Request, Error>>> enqueue(List<Request> requests);

    /**
     * Pause a queued or downloading download.
     *
     * @param ids ids of downloads to be paused.
     * @return Convertible with list of paused downloads. Note. Only downloads that
     * were paused will be returned in the result list.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> pause(List<Integer> ids);

    /**
     * Pause a queued or downloading download.
     *
     * @param id id of download to be paused.
     * @return Convertible with paused download if successful otherwise null.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> pause(int id);

    /**
     * Pause all queued or downloading downloads within the specified group.
     *
     * @param id specified group id.
     * @return Convertible with list of downloads that was paused.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> pauseGroup(int id);

    /**
     * Pauses all currently downloading items, and pauses all download processing fetch operations.
     * Use this method when you do not want Fetch to keep processing downloads
     * but do not want to release the instance of Fetch. However, you are still able to query
     * download information.
     *
     * @return Convertible with action results. True if freeze otherwise false.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Boolean> freeze();

    /**
     * Resume a download that has been paused.
     *
     * @param ids ids of downloads to be resumed.
     * @return Convertible with list of downloads that was successfully resumed.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> resume(List<Integer> ids);

    /**
     * Resume a download that has been paused.
     *
     * @param id id of download to be resumed.
     * @return Convertible with resumed download that was paused.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> resume(int id);

    /**
     * Resume all paused downloads within the specified group.
     *
     * @param id specified group id.
     * @return Convertible with list of resumed downloads.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> resumeGroup(int id);

    /**
     * Allow fetch to resume operations after freeze has been called.
     *
     * @return Convertible with action results. True if unfreeze otherwise false.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Boolean> unfreeze();

    /**
     * Remove a list of downloads managed by this instance of Fetch.
     * The downloaded file for the removed downloads are not deleted.
     *
     * @param ids ids of downloads to be removed.
     * @return Convertible with list of downloads that were removed.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> remove(List<Integer> ids);

    /**
     * Remove a download managed by this instance of Fetch.
     * The downloaded file for the removed download is not deleted.
     *
     * @param id id of download to be removed.
     * @return Convertible with download that was removed if successful.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> remove(int id);

    /**
     * Remove all downloads in the specified group managed by this instance of Fetch.
     * The downloaded files for removed downloads are not deleted.
     *
     * @param id specified group id
     * @return Convertible with list of downloads that were removed.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> removeGroup(int id);

    /**
     * Remove all downloads managed by this instance of Fetch.
     * The downloaded files for removed downloads are not deleted.
     *
     * @return Convertible with list of downloads that were removed.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> removeAll();

    /**
     * Remove all downloads with the specified status in this instance of Fetch.
     * The downloaded files for removed downloads are not deleted.
     *
     * @param status status
     * @return Convertible with list of downloads that were removed.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> removeAllWithStatus(Status status);

    /**
     * Remove all downloads with the specified group and status in this instance of Fetch.
     * The downloaded files for removed downloads are not deleted.
     *
     * @param id id值
     * @param statuses statuses
     * @return Convertible with list of downloads that were removed.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> removeAllInGroupWithStatus(int id, List<Status> statuses);

    /**
     * Delete a list of downloads managed by this instance of Fetch.
     * The downloaded file is deleted.
     *
     * @param ids ids of downloads to be deleted.
     * @return Convertible with list of downloads that were deleted.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> delete(List<Integer> ids);

    /**
     * Delete a download managed by this instance of Fetch.
     * The downloaded file is deleted.
     *
     * @param id id of download to be deleted.
     * @return Convertible with download that was deleted if successful.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> delete(int id);

    /**
     * Deletes all downloads in the specified group managed by this instance of Fetch.
     * The downloaded files are also deleted.
     *
     * @param id specified group id
     * @return Convertible with list of downloads that were deleted.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> deleteGroup(int id);

    /**
     * Deletes all downloads managed by this instance of Fetch.
     * The downloaded files are deleted.
     *
     * @return Convertible with list of downloads that were deleted.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> deleteAll();

    /**
     * Deletes all downloads with the specified status in this instance of Fetch.
     * The downloaded files are also deleted.
     *
     * @param status status
     * @return Convertible with list of downloads that were deleted.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> deleteAllWithStatus(Status status);

    /**
     * Deletes all downloads with the specified group and status in this instance of Fetch.
     * The downloaded files are also deleted.
     *
     * @param id id
     * @param statuses statuses
     * @return Convertible with list of downloads that were deleted.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> deleteAllInGroupWithStatus(int id, List<Status> statuses);

    /**
     * Cancel a list of non completed downloads managed by this instance of Fetch.
     * The downloaded file for the cancelled download is not deleted.
     *
     * @param ids ids of downloads to be cancelled.
     * @return Convertible with list of downloads that were cancelled.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> cancel(List<Integer> ids);

    /**
     * Cancel a non completed download managed by this instance of Fetch.
     * The downloaded file for the cancelled download is not deleted.
     *
     * @param id id of downloads to be cancelled.
     * @return Convertible with download that was cancelled if successful.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> cancel(int id);

    /**
     * Cancels all non completed downloads in the specified group managed by this instance of Fetch.
     * The downloaded files for cancelled downloads are not deleted.
     *
     * @param id specified group id
     * @return Convertible with list of downloads that were cancelled.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> cancelGroup(int id);

    /**
     * Cancels all non completed downloads managed by this instance of Fetch.
     * The downloaded files for cancelled downloads are not deleted.
     *
     * @return Convertible with list of downloads that were cancelled.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> cancelAll();

    /**
     * Retries to download a list of failed or cancelled downloads.
     *
     * @param ids ids of the failed or cancelled downloads.
     * @return Convertible with the list of downloads that were successfully queued.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> retry(List<Integer> ids);

    /**
     * Retries to download a failed or cancelled download.
     *
     * @param id id of the failed or cancelled downloads.
     * @return Convertible with the download that was successfully queued or null.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> retry(int id);

    /**
     * Resets the autoRetryAttempts value for a download back to 0.
     *
     * @param downloadId Id of existing request/download
     * @param retryDownload Retry the download if its status is Status.ERROR. True by default.
     * @return Convertible with the download that was successfully queued or null.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> resetAutoRetryAttempts(int downloadId, Boolean retryDownload);

    /**
     * Updates an existing request.
     *
     * @param requestId Id of existing request/download
     * @param updatedRequest Request object
     * @param notifyListeners If the request is successfully updated notify attached Fetch listeners
     * of the download status. Default true
     * @return Convertible with the successfully updated download or null.
     * @throws FetchException if this instance of Fetch has been closed.
     * @see com.tonyodev.fetch2.Request for more details.
     */
    Convertible<Download> updateRequest(int requestId, Request updatedRequest, Boolean notifyListeners);

    /**
     * Renames the file for a completed download.
     * The StorageResolver attached to this fetch instance will rename the file.
     * So it is okay to parse uri strings for the newFileName.
     *
     * @param id Id of existing request/download
     * @param newFileName the new file name.
     * @return Convertible with the successfully updated download or null.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> renameCompletedDownloadFile(int id, String newFileName);

    /**
     * Replaces the existing extras object associated with an
     * existing download/request with the newly passed in extras object.
     *
     * @param id Id of existing request/download
     * @param extras new extras object
     * @return Convertible with the successfully updated download or null.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> replaceExtras(int id, Extras extras);

    /**
     * Gets all downloads managed by this instance of Fetch.
     *
     * @return Convertible with results.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> getDownloads();

    /**
     * Gets the downloads which match an id in the list. Only successful matches will be returned.
     *
     * @param idList Id list to perform id query against.
     * @return Convertible with results.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> getDownloads(List<Integer> idList);

    /**
     * Gets the download which has the specified id. If the download
     * does not exist null will be returned.
     *
     * @param id Download id
     * @return Convertible with result.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> getDownload(int id);

    /**
     * Gets all downloads in the specified group.
     *
     * @param groupId group id to query.
     * @return Convertible with results.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> getDownloadsInGroup(int groupId);

    /**
     * Gets all downloads with a specific status.
     *
     * @param status Status to query.
     * @return Convertible with results.
     * @throws FetchException if this instance of Fetch has been closed.
     * @see com.tonyodev.fetch2.Status
     */
    Convertible<List<Download>> getDownloadsWithStatus(Status status);

    /**
     * Gets all downloads in a specific group with a specific status.
     *
     * @param groupId group id to query.
     * @param status Statuses to query.
     * @return Convertible with results.
     * @throws FetchException if this instance of Fetch has been closed.
     * @see com.tonyodev.fetch2.Status
     */
    Convertible<List<Download>> getDownloadsInGroupWithStatus(int groupId, List<Status> status);

    /**
     * Gets all downloads containing the identifier.
     *
     * @param identifier identifier.
     * @return Convertible with results.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> getDownloadsByRequestIdentifier(Long identifier);

    /**
     * Gets the FetchGroup by id. Even if the database does not contain downloads with this group id
     * a FetchGroup will be returned. It will contain no downloads however.
     * When a download with this group id is added.
     * The downloads field on this object will be update and attached FetchObservers will be notified.
     *
     * @param group the group id
     * @return Convertible with results.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<FetchGroup> getFetchGroup(int group);

    /**
     * Attaches a FetchListener to this instance of Fetch.
     *
     * @param listener Fetch Listener
     * @return Instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch addListener(FetchListener listener);

    /**
     * Attaches a FetchListener to this instance of Fetch.
     *
     * @param listener Fetch Listener
     * @param notify Allows Fetch to notify the newly attached listener instantly of the download status
     * of all downloads managed by the namespace. Default is false.
     * @return Instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch addListener(FetchListener listener, Boolean notify);

    /**
     * Attaches a FetchListener to this instance of Fetch.
     *
     * @param listener Fetch Listener
     * @param notify Allows Fetch to notify the newly attached listener instantly of the download status
     * of all downloads managed by the namespace. Default is false.
     * @param autoStart Allows Fetch to start processing requests if it is not already doing so.
     * @return Instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch addListener(FetchListener listener, Boolean notify, Boolean autoStart);

    /**
     * Detaches a FetchListener from this instance of Fetch.
     *
     * @param listener Fetch Listener
     * @return Instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch removeListener(FetchListener listener);

    /**
     * Adds a completed download to Fetch for management.
     * If Fetch is already managing another download with the same file as this completed download's
     * file, Fetch will replace the already managed download with this completed download.
     *
     * @param completedDownload Completed Download
     * @param alertListeners boolean indicating whether to alert all listeners attached to
     * this fetch's namespace of the downloads completed status.
     * @return Instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Download> addCompletedDownload(CompletedDownload completedDownload, Boolean alertListeners);

    /**
     * Adds a list of completed downloads to Fetch for management.
     * If Fetch is already managing another download with the same file as this completed download's
     * file, Fetch will replace the already managed download with this completed download.
     *
     * @param completedDownloads Completed Downloads list
     * @param alertListeners boolean indicating whether to alert all listeners attached to
     * this fetch's namespace of the downloads completed status.
     * @return Convertible
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<Download>> addCompletedDownloads(List<CompletedDownload> completedDownloads,
                                                      Boolean alertListeners);

    /**
     * Gets the list of download blocks belonging to a download. List may be empty if
     * blocks could not be found for the download id or download has never been processed.
     *
     * @param downloadId Download ID
     * @return Convertible
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<DownloadBlock>> getDownloadBlocks(int downloadId);

    /**
     * Enable or disable logging.
     *
     * @param enabled Enable or disable logging.
     * @return Instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch enableLogging(Boolean enabled);

    /**
     * Overrides each downloads specific network type preference and uses a
     * global network type preference instead.
     * Use com.tonyodev.fetch2.NetworkType.GLOBAL_OFF to disable the global network preference.
     * The default value is com.tonyodev.fetch2.NetworkType.GLOBAL_OFF
     *
     * @param networkType The global network type.
     * @return Instance
     * @throws FetchException if this instance of Fetch has been closed.
     * @see com.tonyodev.fetch2.NetworkType
     */
    RxFetch setGlobalNetworkType(NetworkType networkType);

    /**
     * Sets the number of parallel downloads Fetch should perform at any given time.
     * Default value is 1. This method can only accept values greater than 0. Setting
     * concurrent limit to zero prevents the instance of Fetch to pull and download request
     * from the waiting queue but allows the instance of Fetch to act on and observe changes to
     * requests/downloads.
     *
     * @param downloadConcurrentLimit Number of parallel downloads.
     * @return Instance
     * @throws FetchException if the passed in download concurrent limit is less than 0 or
     * Fetch instance has been closed.
     */
    RxFetch setDownloadConcurrentLimit(int downloadConcurrentLimit);

    /**
     * Releases held resources and the namespace used by this Fetch instance.
     * Once closed this instance cannot be reused but the namespace can be reused
     * by a new instance of Fetch.
     */
    void close();

    /**
     * Gets the set of FetchListeners attached to this instance.
     *
     * @return set of attached FetchListeners.
     */
    Set<FetchListener> getListenerSet();

    /**
     * Gets the content Length for a request. If the request or contentLength cannot be found in
     * the Fetch database(meaning Fetch never processed the request and started downloading it) -1 is returned.
     * However, setting fromServer to true will create a new connection to the server to get the connectLength
     * if Fetch does not already contain the data in the database for the request.
     *
     * @param request Request. Can be a managed or un-managed request. The request is not stored in
     * the fetch database.
     * connection to get the contentLength
     * @param fromServer If true, fetch will attempt to get the ContentLength
     * from the server directly by making a network request. Otherwise no action is taken.
     * @return Convertible with content length result. If value is -1. This means that Fetch was
     * not able to get the content length.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Long> getContentLengthForRequest(Request request, Boolean fromServer);

    /**
     * Gets the content Length for each request in the passed in list.
     * If the request or contentLength cannot be found in
     * the Fetch database(meaning Fetch never processed the request and started downloading it) -1 is returned.
     * However, setting fromServer to true will create a new connection to the server to get the connectLength
     * if Fetch does not already contain the data in the database for the request.
     *
     * @param requests Request list. Can be a managed or un-managed list of requests. The requests are not stored in
     * the fetch database.
     * @param fromServer If true, fetch will attempt to get the ContentLength
     * from the server directly by making a network request. Otherwise no action is taken.
     * @return convertible containing the success and error result list.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<Pair<List<Pair<Request, Long>>, List<Pair<Request, Error>>>> getContentLengthForRequests(
        List<Request> requests, Boolean fromServer);

    /**
     * Gets the Server Response for the url and associated headers.
     *
     * @param url the url. Cannot be null.
     * @param headers the request headers for the url. Can be null.
     * @return Convertible with the server response.
     * @throws FetchException if this instance of Fetch has been closed.
     * @throws java.io.IOException if the the server request was not successful.
     */
    Convertible<Downloader.Response> getServerResponse(String url, Map<String, String> headers);

    /**
     * Gets the full Catalog of a Fetch File Server.
     *
     * @param request Request. Can be a managed or un-managed request. The request is not stored in
     * the fetch database.
     * @return Convertible with catalog results.
     * @throws FetchException if this instance of Fetch has been closed.
     */
    Convertible<List<FileResource>> getFetchFileServerCatalog(Request request);

    /**
     * Blocks the current thread(Not Ui Thread) to waiting on one of the two conditions.
     * Condition One: Waits until Fetch has downloaded all downloading and pending downloads.
     * Condition Two: Waits until the allow time expires
     * if Fetch has not completed or attempted to download queued downloads.
     * This method returns when one of the conditions if violated.
     * Note: Calling this method on the UIThread is strongly discouraged and an exception is thrown.
     *
     * @param allowTimeInMilliseconds the allowed time in milliseconds. If zero the wait is indefinite.
     * @throws FetchException if calling on the main thread
     */
    void awaitFinishOrTimeout(long allowTimeInMilliseconds);

    /**
     * Blocks the current thread(Not Ui Thread) to waiting on the current conditions.
     * Condition One: Waits until Fetch has downloaded all downloading and pending downloads.
     * This method returns when one of the conditions if violated.
     * Note: Calling this method on the UIThread is strongly discouraged and an exception is thrown.
     *
     * @throws FetchException if calling on the main thread
     */
    void awaitFinish();

    /**
     * Attaches a FetchObserver to listen for changes on a download managed by this Fetch namespace.
     * FetchObservers are held with a weak reference. Note: If fetch does not manage a download with
     * the passed in id, the FetchObserver will not be notified. Only when a download with the specified
     * id is managed by Fetch will the observer be called.
     *
     * @param downloadId the download Id
     * @param fetchObservers the fetch observers
     * @return instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch attachFetchObserversForDownload(int downloadId, FetchObserver<Download> fetchObservers);

    /**
     * Removes a FetchObserver attached to this Fetch namespace for a download.
     *
     * @param downloadId the download Id
     * @param fetchObservers the fetch observers
     * @return instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch removeFetchObserversForDownload(int downloadId, FetchObserver<Download> fetchObservers);

    /**
     * Indicates if this fetch namespace has active(Queued or Downloading) downloads. You can use this value to
     * keep a background service ongoing until the results returns false.
     *
     * @param includeAddedDownloads To include downloads with a status of Added.
     * Added downloads are not considered active.
     * @return Convertible with results.
     * @throws FetchException if accessed on ui thread
     */
    Convertible<Boolean> hasActiveDownloads(Boolean includeAddedDownloads);

    /**
     * Subscribe a FetchObserver that indicates if this fetch namespace has active(Queued or Downloading) downloads.
     * You can use this value to keep a background service ongoing until the value returned is false.
     *
     * @param includeAddedDownloads To include downloads with a status of Added.
     * Added downloads are not considered active by default.
     * @param fetchObserver the fetch observer
     * @return instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch addActiveDownloadsObserver(Boolean includeAddedDownloads, FetchObserver<Boolean> fetchObserver);

    /**
     * Removes a subscribed FetchObserver that is listening for active downloads.
     *
     * @param fetchObserver the fetch observer to remove.
     * @return instance
     * @throws FetchException if this instance of Fetch has been closed.
     */
    RxFetch removeActiveDownloadsObserver(FetchObserver<Boolean> fetchObserver);

    /**
     * RX Fetch implementation class. Use this Singleton to get instances of RxFetch or Fetch.
     *
     * @since 2021-05-20
     */
    public static final class Impl {
        private static final Object lock = new Object();
        private static volatile FetchConfiguration defaultRxFetchConfiguration;
        private static volatile RxFetch defaultRxFetchInstance;

        /**
         * Sets the default Configuration settings on the default Fetch instance.
         *
         * @param fetchConfiguration custom Fetch Configuration
         */
        public static void setDefaultRxInstanceConfiguration(FetchConfiguration fetchConfiguration) {
            synchronized (lock) {
                defaultRxFetchConfiguration = fetchConfiguration;
            }
        }

        /**
         * Get the default Fetch Configuration
         * set with setDefaultInstanceConfiguration(fetchConfiguration: FetchConfiguration)
         * or setDefaultInstanceConfiguration(context: Context)
         *
         * @return default FetchConfiguration
         */
        FetchConfiguration getDefaultRxFetchConfiguration() {
            return defaultRxFetchConfiguration;
        }

        /**
         * 获取默认配置的RxFetch
         *
         * @return Get default RxFetch instance
         * @throws FetchException if default FetchConfiguration is not set.
         */
        public static RxFetch getDefaultRxInstance() {
            RxFetch rxFetch = null;
            try {
                FetchConfiguration configuration = defaultRxFetchConfiguration;
                if (configuration == null) {
                    throw (Throwable) (new FetchException("Global Fetch Configuration not set"));
                }

                FetchConfiguration rxFetchConfiguration = configuration;
                RxFetch defaultRxFetch = defaultRxFetchInstance;
                RxFetch fetch = null;
                if (defaultRxFetch == null || defaultRxFetch.isClosed()) {
                    RxFetchImpl newDefaultRxFetch = RxFetchImpl.newInstance(
                        FetchModulesBuilder.getInstance().buildModulesFromPrefs(rxFetchConfiguration));
                    defaultRxFetchInstance = (RxFetch) newDefaultRxFetch;
                    fetch = (RxFetch) newDefaultRxFetch;
                } else {
                    fetch = defaultRxFetch;
                }
                rxFetch = fetch;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            return rxFetch;
        }

        /**
         * Creates a custom Instance of Fetch with the given configuration and namespace.
         *
         * @param fetchConfiguration custom Fetch Configuration
         * @return custom RxFetch instance
         */
        public static RxFetch getRxInstance(FetchConfiguration fetchConfiguration) {
            return RxFetchImpl.newInstance(FetchModulesBuilder.getInstance().buildModulesFromPrefs(fetchConfiguration));
        }
    }
}
